#include <QtGui/QApplication>
#include "widget.h"

#if 0x0
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}
#endif

extern "C"
{
#define UINT64_C(c)     c ## ULL
#include "libavformat/avformat.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/audioconvert.h"
#include "libavcodec/colorspace.h"
#include "libavcodec/opt.h"
#include "libavcodec/avfft.h"

//#include <avcodec.h>
//#include <avcodec.h>
//#include <avformat.h>
}

#include <QtCore>
#include <QtGui>

//#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    AVFormatContext	*formatCtx;
    int		videoStream;
    AVCodecContext	*codecCtx;
    AVCodec		*codec;
    AVFrame		*frame;
    AVFrame		*frameRGB;
    AVPacket	packet;
    int		frameFinished;
    int		numBytes;
    uint8_t		*buffer;
    PixelFormat pixfmt=PIX_FMT_BGRA;
    QString		filename;

    if(argc>=2)
        filename=argv[1];
    else
        filename="sample.mov";

    qDebug() << filename;

    av_register_all();
    if(av_open_input_file(&formatCtx, filename.toLocal8Bit().constData(), NULL, 0, NULL)) {
        qDebug() << "Can't open video";
        return 1;
    }

    if(av_find_stream_info(formatCtx)<0) {
        qDebug() << "Can't find stream info";
        return 1;
    }

    dump_format(formatCtx, 0, filename.toLocal8Bit().constData(), false);

    videoStream=-1;
    for(unsigned int i=0; i<formatCtx->nb_streams; i++)
        if(formatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
            videoStream=i;
            break;
        }
    if(videoStream<0) {
        qDebug() << "No video stream.";
        return 1;
    }

    codecCtx=formatCtx->streams[videoStream]->codec;
    codec=avcodec_find_decoder(codecCtx->codec_id);
    if(!codec) {
        qDebug() << "Unsupported codec.";
        return 1;
    }

    if(avcodec_open(codecCtx, codec)<0) {
        qDebug() << "avcodec_open failed";
        return 1;
    }

    frame=avcodec_alloc_frame();
    frameRGB=avcodec_alloc_frame();
    if(!frameRGB) {
        qDebug() << "alloc RGB frame failed.";
        return 1;
    }

    numBytes=avpicture_get_size(
            (enum PixelFormat)pixfmt,
            codecCtx->width,
            codecCtx->height
            );
    buffer=new uint8_t[numBytes];
    avpicture_fill(
            reinterpret_cast<AVPicture*>(frameRGB),
            buffer,
            (enum PixelFormat)pixfmt,
            codecCtx->width,
            codecCtx->height
            );

    int frameNo=0;
    while(av_read_frame(formatCtx, &packet)>=0) {
        if(packet.stream_index==videoStream) {
            avcodec_decode_video(codecCtx, frame, &frameFinished, packet.data, packet.size);
            if(frameFinished) {
                qDebug() << "[frameNo]" << frameNo;
                qDebug() << "[codecCtx->pix_fmt]" << (int)codecCtx->pix_fmt;
                qDebug() << "[pixfmt]" << pixfmt;
                SwsContext *v_sws_ctx = sws_getContext(
                        codecCtx->width, //int srcW,
                        codecCtx->height, //int srcH,
                        codecCtx->pix_fmt, //enum PixelFormat srcFormat,
                        codecCtx->width, //int dstW,
                        codecCtx->height, //int dstH,
                        (enum PixelFormat)pixfmt, //enum PixelFormat dstFormat,
                        SWS_BICUBIC, //int flags,
                        NULL, //SwsFilter *srcFilter,
                        NULL, //SwsFilter *dstFilter,
                        NULL  //const double *param
                        );
                int v_scale_result = sws_scale(
                        v_sws_ctx,
                        frame->data,
                        frame->linesize,
                        0,
                        codecCtx->height,
                        frameRGB->data,
                        frameRGB->linesize
                        );
                qDebug() << "[v_scale_result]" << v_scale_result;
                sws_freeContext(v_sws_ctx);
                QImage img(
                        frameRGB->data[0],
                        codecCtx->width,
                        codecCtx->height,
                        QImage::Format_ARGB32
                        );
                qDebug() << img.isNull();
                if(!img.isNull())
                {
                    img.save("frame" + QString::number(frameNo++) + ".png", "PNG");
                    //img.save("frame" + QString::number(frameNo++) + ".jpg", "JPEG");
                    qDebug() << img.valid(0, 0);
                }
            }
        }
        av_free_packet(&packet);
        //if(frameNo==100) break;
        if(frameNo==10) break;
    }
    delete[] buffer;
    av_free(frameRGB);
    av_free(frame);
    avcodec_close(codecCtx);
    av_close_input_file(formatCtx);
    return 0;
}
